package com.cat.myblog.common.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.cat.myblog.common.vo.ResponseResult;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Slf4j
public class JsonUtil {

    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");

    private JsonUtil() {
    }

    public final static ObjectMapper MAPPER;

    static {
        MAPPER = serializingObjectMapper();
    }

    /**
     * 将对象序列化为JSON字符串。
     *
     * @param obj 要序列化的对象。
     * @return 如果序列化成功，返回JSON字符串；如果失败，则抛出运行时异常。
     * @throws RuntimeException 如果在序列化过程中发生任何错误，将抛出此异常，并包含详细的错误信息。
     */
    public static String serialize(Object obj) {
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.error("Object转JSONString失败：{}", e.getMessage());
        }
        return null;
    }


    /**
     * 将JSON字符串反序列化为Java对象。
     *
     * @param jsonText 待反序列化的JSON字符串。
     * @param type     目标类型的TypeReference，用于指定反序列化后的Java对象类型。
     * @return 反序列化后的Java对象，如果反序列化失败则返回null。
     * @throws Exception 如果在反序列化过程中发生任何异常，则捕获并打印堆栈跟踪，但不会重新抛出异常。
     */
    public static Object deserialize(String jsonText, TypeReference type) {
        try {
            return MAPPER.readValue(jsonText, type);
        } catch (Exception e) {
            log.error("Json转Object失败：{}", e.getMessage());
        }
        return null;
    }


    /**
     * 将JSON字符串反序列化为指定的Java对象类型。
     *
     * @param <T>        反序列化后的目标类型。
     * @param jsonText   待反序列化的JSON字符串。
     * @param beanClass   目标类型的Class对象，用于指定反序列化后的Java对象类型。
     * @return 如果反序列化成功，则返回指定类型的Java对象；如果失败，则返回null。
     * @throws Exception 如果在反序列化过程中发生异常，则会捕获该异常并打印堆栈跟踪，但不会重新抛出异常。
     */
    public static <T> T deserialize(String jsonText, Class<T> beanClass) {
        try {
            return MAPPER.readValue(jsonText, beanClass);
        } catch (Exception e) {
            log.error("Json转 {}Object失败：{}",beanClass.getName(), e.getMessage());
        }
        return null;
    }


    /**
     * 将对象转换为Map。
     *
     * @param objEntity 要转换的对象。
     * @return 如果转换成功，返回包含对象属性的Map；如果objEntity为null或转换失败，则返回null。
     * @throws JsonProcessingException 如果在JSON处理过程中发生异常，则会捕获该异常并打印堆栈跟踪，但函数不会直接抛出异常。
     */
    public static Map toMap(Object objEntity) {
        if (Objects.isNull(objEntity)) {
            return null;
        }
        Map map = new HashMap();
        try {
            map = MAPPER.readValue(MAPPER.writeValueAsString(objEntity), Map.class);
        } catch (JsonProcessingException e) {
            log.error("Object转Map失败  ：{}", e.getMessage());
        }
        return map;
    }

    /**
     * jackson2 json序列化 null字段输出为空串
     */
    public static ObjectMapper serializingObjectMapper() {

        //设置日期格式
        ObjectMapper objectMapper = new ObjectMapper();

        JavaTimeModule javaTimeModule = new JavaTimeModule();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //序列化   日期格式
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer());
        javaTimeModule.addSerializer(Date.class, new DateSerializer(false, simpleDateFormat));
        //反序列化    日期格式
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer());
        javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
            @Override
            public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                String date = jsonParser.getText();
                try {
                    return simpleDateFormat.parse(date);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        objectMapper.registerModule(javaTimeModule)
                //配置序列化时忽略null值
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                //配置反序列化时忽略不存在的字段
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

        //序列化成json时，将所有的Long变成string，以解决js中的精度丢失。
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);

        //忽略不存在的字段
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }




    /**
     * LocalDateTime序列化
     */
    private static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.format(DATETIME_FORMATTER));
        }
    }

    /**
     * LocalDateTime反序列化
     */
    private static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return LocalDateTime.parse(p.getValueAsString(), DATETIME_FORMATTER);
        }
    }

    /**
     * LocalDate序列化
     */
    private static class LocalDateSerializer extends JsonSerializer<LocalDate> {

        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {

            // 获取value来源的类
            Class<?> aClass = gen.getCurrentValue().getClass();

            // 获取字段名
            String currentName = gen.getOutputContext().getCurrentName();

            try {
                // 获取字段
                Field declaredField = aClass.getDeclaredField(currentName);
                // 校验是否LocalDate属性的字段
                if (Objects.equals(declaredField.getType(), LocalDate.class)) {
                    // 是否被@JsonFormat修饰
                    boolean annotationPresent = declaredField.isAnnotationPresent(JsonFormat.class);

                    if (annotationPresent) {
                        String pattern = declaredField.getAnnotation(JsonFormat.class).pattern();
                        if (StringUtils.isNotEmpty(pattern)) {
                            gen.writeString(value.format(DateTimeFormatter.ofPattern(pattern)));
                        } else {
                            gen.writeString(value.format(DATE_FORMATTER));

                        }
                    } else {
                        gen.writeString(value.format(DATE_FORMATTER));
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * LocalDate反序列化
     */
    private static class LocalDateDeserializer extends JsonDeserializer<LocalDate> {

        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return LocalDate.parse(p.getValueAsString(), DATE_FORMATTER);
        }
    }

    /**
     * LocalTime序列化
     */
    private static class LocalTimeSerializer extends JsonSerializer<LocalTime> {

        @Override
        public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.format(TIME_FORMATTER));
        }
    }

    /**
     * LocalTime反序列化
     */
    private static class LocalTimeDeserializer extends JsonDeserializer<LocalTime> {

        @Override
        public LocalTime deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
            return LocalTime.parse(p.getValueAsString(), TIME_FORMATTER);
        }
    }
}

